"use strict";
var _async = require("async");
var _lruCache = _interopRequireDefault(require("lru-cache"));
var _utils = require("../../../utils");
var _configCenter = _interopRequireDefault(require("../../../config-center"));
var _request = require("../../../utils/request");
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
/**
 * 1. N个书源，N个队列
 * 2. 限制并发数量
 */ const MAX_POOL_SIZE = 10000;
const MAX_POOL_AGE = 20 * 60 * 1000; // 缓存 20 min
const MAX_TASK_SIZE = Math.floor(MAX_POOL_SIZE / _configCenter.default.configs.size * 0.67);
let NoverRequestCore = class NoverRequestCore {
    async analyzeContent(payload) {
        const { url , data , timeout =5000 , method , headers  } = payload;
        if (method === 'get') {
            return (0, _request).craw(url, {
                timeout,
                headers
            });
        }
        return (0, _request).postCrawl(url, data, {
            timeout,
            headers
        });
    }
    getUniqueKey(payload) {
        const { url , method , data ={}  } = payload;
        const dataStr = typeof data === 'string' ? data : Object.keys(data).map((k)=>`${k}:${k[data]}`
        ).join('');
        const uniqueKey = `${method}-${url}_${dataStr}`;
        return uniqueKey;
    }
    getCurrentSite(payload) {
        const { url  } = payload;
        const currentSite = _configCenter.default.supportedSites.find((i)=>url.includes(i)
        );
        if (!currentSite) {
            throw new Error('task create failed, unsupported site');
        }
        return currentSite;
    }
    pushTask(payload, useCache) {
        const uniqueKey = this.getUniqueKey(payload);
        const currentSite = this.getCurrentSite(payload);
        if (this.workingList[currentSite].has(uniqueKey)) {
            return true;
        }
        if (useCache && this.resultPool.has(uniqueKey)) {
            return true;
        }
        if (this.wrokers[currentSite].length() > MAX_TASK_SIZE) {
            throw new Error('task create failed, over limit');
        }
        this.wrokers[currentSite].push(payload);
        return true;
    }
    async push(payload, useCache = true) {
        this.pushTask(payload, useCache);
        var _timeout;
        const fetchCnt = Math.round(((_timeout = payload.timeout) != null ? _timeout : 5000) / 500);
        for(let i = 0; i < fetchCnt; i++){
            const result = this.resultPool.get(this.getUniqueKey(payload));
            if (result) {
                return result;
            }
            await (0, _utils).delay(500);
        }
        throw new Error('wait timeout');
    }
    constructor(){
        this.wrokers = {};
        this.workingList = {};
        this.resultPool = new _lruCache.default({
            max: MAX_POOL_SIZE,
            maxAge: MAX_POOL_AGE
        });
        this.init = ()=>{
            _configCenter.default.configs.forEach((config, key)=>{
                this.workingList[key] = new Set();
                var ref;
                this.wrokers[key] = (0, _async).queue((payload, callback)=>{
                    const { url  } = payload;
                    const uniqueKey = this.getUniqueKey(payload);
                    this.workingList[key].add(url);
                    this.analyzeContent(payload).then((val)=>this.resultPool.set(uniqueKey, val)
                    ).catch(()=>undefined
                    ).finally(()=>{
                        this.workingList[key].delete(url);
                        callback();
                    });
                }, (ref = config == null ? void 0 : config.concurrency) != null ? ref : 6);
            });
        };
        _configCenter.default.addConfigListener(this.init);
    }
};
/** 全局唯一 */ module.exports = new NoverRequestCore();
